#!/bin/python

import re
import sys

def usage():
	print """
	%s [options] infile outfile
	
	options:
		-v	Specify a value on the command line 
			to replace into the template
			
		-f	Specify a file to read as a value 
			to be replaced into the template
			
		-t	Specify a title to be placed into 
			the <title> tag
		
		-m	Specify a <meta> tag. It will only 
			replace an existing tag	and will not 
			create a new tag
			
	example:
		%s -v title="this is the title" \
		-f content=body.html \
		-m description="this is the description" \
		template.html outfile.html
		
		This will replace the contents of an html 
		block with the id attribute set to
		'title' with "this is the title" and will 
		load the contents of 'body.html' into
		the html block with the id set to 'content'. 
		The description will be replaced into an 
		existing description meta tag	
		
	""" % (sys.argv[0], sys.argv[0])
	
def get_body(html):
	"""
	Extracts only the text between <body> tags from html
	This is useful if you use an editor to create the html snippets
	"""
	
	searchstr = "<body(\\s+\\w+\\s*=\\s*\"\\w*\")*\\s*>"
	match = re.compile(searchstr, re.MULTILINE | re.IGNORECASE).search(html)
	if match == None:
		return html
	else:
		startpos = html.find(match.group(0)) + len(match.group(0))
		endpos = html.find('</body>')
		return html[startpos:endpos]
		
def extract_title(html):
	startpos = html.find('<title>')
	endpos = html.find('</title>')
	if startpos < 0 or endpos < 0:
		return None
	else:
		return html[startpos+len('<title>'):endpos]
	
def extract_meta(html, name):
	searchstr = "<meta(\\s+(\\w+\\s*=\\s*\"\\w*\"))*\\s*>"
	match = re.compile(searchstr, re.MULTILINE | re.IGNORECASE).search(html)
		
def replace_title(html, str):
	startpos = html.find('<title>')
	endpos = html.find('</title>')
	if startpos < 0 or endpos < 0:
		print "I cannot find the <head> tag or it may be malformed"
		usage()
		sys.exit(2)
	else:
		return html[:startpos+len('<title>')] + str + html[endpos:]
		
def replace_meta(html, name, str):
	"""
	Search html for a meta tag where the name attribute
	equals name and replace the content attribute
	with str
	"""

	searchstr = "<meta\\s+name\\s*=\\s*\"" + name + "\"\\s*content=\"(\w*)\"\\s*>"
	match = re.compile(searchstr, re.MULTILINE | re.IGNORECASE).search(html)
	
	if match == None:
		return html
	else:
		return html.replace(match.group(0), '<meta name="' + name + '" content="' + str.replace('"','\\"') + '">') 
		
	
def replace_contents(html, id, str):

	"""
	Replaces the contents of an html block between the tags where id
	matches the id attribute
	"""
	
	searchstr = "<(\\w+)(\\s+\\w+\\s*=\\s*\"\\w*\")*\\s*id=\"" + id + "\"(\\s+\\w+\\s*=\\s*\"\\w*\")*\\s*>"
	match = re.compile(searchstr, re.MULTILINE | re.IGNORECASE).search(html)
	
	if match == None:
		return html
		
	startpos = html.find(match.group(0)) + len(match.group(0))
	tag = match.group(1)
	tagcount = 1  # count the opening tag - a count of 0 means the tag has been closed
	curpos = startpos #start searching for the closing tag here
	
	while tagcount > 0:
		next_open_pos = html[curpos:].find("<"+tag)
		next_close_pos = html[curpos:].find("</"+tag)
		
		if next_open_pos < next_close_pos and next_open_pos > 0:
			tagcount = tagcount + 1	
			curpos = curpos + next_open_pos + len("<"+tag)
		else:
			tagcount = tagcount - 1 
			curpos = curpos + next_close_pos + len("</"+tag)
				
	endpos = curpos - len("</"+tag)
	return html[0:startpos] + str + html[endpos:]
	
def main(args):
	import getopt
	try:
		opts, args = getopt.getopt(args, 'v:f:t:m:')
	except getopt.GetoptError, err:
		print (err)
		usage()
		sys.exit(2)
		
	if len(args) == 2:	# a source and destination file needs to be specified
		infile = args[0]
		outfile = args[1]
		title = None
		metadict = {}
		replacedict = {}
		
		for opt, value in opts:
			if opt == '-f':
				# a file has been specified - load it and use it as a value
				key, val = value.split('=')
				try:					
					f = file(val,'r')
					txt = f.read()
				finally:
					f.close() 
				replacedict[key] = getbody(txt) #only get the body part from html files - useful for html editors like Kompozer
				
			elif opt == '-v':
				key, val = value.split('=')
				replacedict[key] = val
			
			elif opt == '-t':
				title = value
				
			elif opt == '-m':
				key, val = value.split('=')
				metadict[key] = val
				
			else:
				print "Unhandled option: " + opt
				usage()
				sys.exit(2)
				
		try: #open the template file (infile)
			f = file(infile,'r')
			template = f.read()
		finally:
			f.close()
				
		for key in replacedict:
			template = replace_contents(template, key, replacedict[key])
			
		for key in metadict:
			template = replace_meta(template, key, metadict[key])
			
		if title is not None:
			template = replace_title(template, title)
			
		try: #open the result file for writing (outfile)
			f = file(outfile,'w')
			f.write(template)
		finally:
			f.close()
	
	
if __name__ == "__main__":
	main(sys.argv[1:])
	
